package net.pulseproject.router.debuggerapp.view;

import java.awt.event.ActionEvent;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

import javax.sound.midi.MidiMessage;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.ShortMessage;
import javax.swing.BoxLayout;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

import net.pulseproject.commons.gui.ActionListenerX;
import net.pulseproject.commons.gui.IconsCache;
import net.pulseproject.commons.midi.DebuggerLogic;
import net.pulseproject.commons.midi.entity.Device;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

class ReceivePanel extends JPanel {

	private static final long serialVersionUID = -7536423248093187047L;

	private static final Log LOG = LogFactory.getLog(ReceivePanel.class);
	
	private static final DateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss.SSS");
	

	private final Device port;
	
	private final JTextArea receivedMessagesText = new JTextArea();
	
	private final DebuggerLogic logic;

	private final IconsCache iconsCache;
	
	public ReceivePanel(final IconsCache iconsCache, final JFrame parent, final DebuggerLogic logic, final Device port) {
		this.iconsCache = iconsCache;
		this.logic = logic;
		this.port = port;
		
		this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
		
		final JCheckBox check = new JCheckBox("Receive enabled");
		check.setEnabled(port.getState().isTransmitting());
		check.addActionListener(new ActionListenerX(this.iconsCache, parent, "Could not enable receiver!") {
			@Override protected void action(final ActionEvent event) {
				ReceivePanel.this.doEnable(check.isSelected());
		}});
		this.add(check);
		
//		this.receivedMessagesText.setLineWrap(true);
//		this.receivedMessagesText.setColumns(20);
		this.receivedMessagesText.setColumns(32);
		this.receivedMessagesText.setRows(20);
		this.add(new JScrollPane(this.receivedMessagesText));
	}
	
	private void doEnable(final boolean enable) {
		LOG.debug("doEnable(enable=" + enable + ")");
		
		if(enable == true) {
			try {
				this.logic.addReceiver(this.port.getPortName(), new Receiver() {
					@Override public void send(final MidiMessage message, final long timeStamp) {
						ReceivePanel.this.receivedMessage(message, timeStamp);
					}
					@Override public void close() {
						LOG.debug("close()");
						ReceivePanel.this.appendToTextArea("MIDI port closed");
					}
				});
			} catch (final MidiUnavailableException e) {
				throw new RuntimeException("Could not add receiver on port [" + this.port.getPortName() + "]!", e);
			}
		} else {
			System.out.println("TODO disable MIDI receive"); // TODO implement disable MIDI receive
		}
	}
	
	private void receivedMessage(final MidiMessage message, @SuppressWarnings("unused") final long timeStamp) {
		LOG.debug("receivedMessage(..) ... Received sent MIDI data at port '" + this.port.getPortName() + "': " + 
				Arrays.toString(message.getMessage()));
		
		final ShortMessage sm = (ShortMessage) message;
		
		final String newText =
			TIME_FORMAT.format(new Date()) + " " +
			"status: " + sm.getStatus() + " " + // TODO also display name of status (e.g.: 157 == NOTE_ON_CHANNEL_14)
//			"command: " + sm.getCommand() + ", " +
			"channel: " + sm.getChannel() + ", " +
			"data1: " + sm.getData1() + ", " +
			"data2: " + sm.getData2();
		
		this.appendToTextArea(newText);
	}
	
	private void appendToTextArea(final String newText) {
		final String oldText = this.receivedMessagesText.getText();
		this.receivedMessagesText.setText(newText + "\n" + oldText);
	}
}
